package com.luoran.bartalks.action;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.luoran.bartalks.action.vo.EChartsVo;
import com.luoran.bartalks.core.UserContext;
import com.luoran.bartalks.entity.biz.BtPlanEntry;
import com.luoran.bartalks.service.IBtEChartsService;
import com.luoran.bartalks.utils.DateFormatUtils;

/**
 * 
 * @ClassName: BtVisualizationAction
 * @Description: 数据可视化
 * @author: M1nG
 * @date: 2019年1月14日 上午10:39:11
 */
@Controller
@RequestMapping("report/visualization")
public class BtVisualizationAction {

	private final static Logger log = LoggerFactory.getLogger(BtInitBasicInfoAction.class);

	@Autowired
	private IBtEChartsService service;

	@RequestMapping
	public String show() {
		return "visualization/visualization";
	}

	/**
	 * 获取title数据
	 * 
	 * @return JSON
	 */
	@RequestMapping("/getTitle")
	@ResponseBody
	public JSONObject getTitle(@RequestParam(value = "startTime", required = true, defaultValue = "") String startTime,
			@RequestParam(value = "endTime", required = true, defaultValue = "") String endTime,
			@RequestParam(value = "project", required = true, defaultValue = "all") String project) {
		log.info("获取title数据");
		if (startTime == null || "".equals(startTime)) {
			startTime = DateFormatUtils.dateMath("year", -1);
		}
		if (endTime == null || "".equals(endTime)) {
			endTime = DateFormatUtils.Date2StrFinalNow(new Date());
		}
		JSONObject res = new JSONObject();
		JSONObject data = new JSONObject();
		String companyId = UserContext.get().getCompanyId();
		Map<String, Integer> titleData = service.getTitle(companyId, startTime, endTime);
		data = JSONObject.parseObject(JSON.toJSONString(titleData));
		res.put("data", data);
		res.put("state", true);
		return res;
	}

	/**
	 * 获取scatter数据
	 * 
	 * @return JSON
	 */
	@RequestMapping("/getScatter")
	@ResponseBody
	public JSONObject getScatter(
			@RequestParam(value = "startTime", required = true, defaultValue = "") String startTime,
			@RequestParam(value = "endTime", required = true, defaultValue = "") String endTime,
			@RequestParam(value = "project", required = true, defaultValue = "all") String project) {
		log.info("获取scatter数据");
		if (startTime == null || "".equals(startTime)) {
			startTime = DateFormatUtils.dateMath("year", -1);
		}
		if (endTime == null || "".equals(endTime)) {
			endTime = DateFormatUtils.Date2StrFinalNow(new Date());
		}
		JSONObject res = new JSONObject();
		String companyId = UserContext.get().getCompanyId();
		List<EChartsVo> scatterList = service.getScatter(companyId, startTime, endTime);
		if (scatterList == null) {
			res.put("state", false);
			res.put("msg", "系统错误，获取计划地点货物量数据失败！");
			return res;
		} else if (scatterList.size() == 0) {
			res.put("state", false);
			res.put("msg", "计划地点货物量无数据返回！");
			return res;
		} else {
//			List<EChartsVo> location = scatterList.stream()
//					.collect(Collectors.collectingAndThen(Collectors.toCollection(
//							// 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
//							// 根据id去重
//							() -> new TreeSet<>(Comparator.comparing(EChartsVo::getId))), ArrayList::new));
			// 判断时间有多少周
//			int dateMathNumber = DateFormatUtils.dateMathNumber(DateFormatUtils.Str2Date(startTime),
//					DateFormatUtils.Str2Date(endTime), "year");
			for (EChartsVo e : scatterList) {
				Map<Integer, Integer> map = new HashMap<Integer, Integer>();
				for (int j = 0; j < 53 + 1; j++) {
					map.put(j, 0);
				}
				List<EChartsVo> scatterNumber = service.getScatterNumber(startTime, endTime, e.getId());
				for (EChartsVo num : scatterNumber) {
					map.put(num.getType(), num.getNumber());
				}
				e.setList(new ArrayList<Integer>(map.values()));
			}
		}
		res.put("data", scatterList);
		res.put("state", true);
		return res;
	}

	/**
	 * 获取sankey数据
	 * 
	 * @return JSON
	 */
	@RequestMapping("/getSankey")
	@ResponseBody
	public JSONObject getSankey(@RequestParam(value = "startTime", required = true, defaultValue = "") String startTime,
			@RequestParam(value = "endTime", required = true, defaultValue = "") String endTime,
			@RequestParam(value = "project", required = true, defaultValue = "all") String project) {
		log.info("获取sankey数据");
		if (startTime == null || "".equals(startTime)) {
			startTime = DateFormatUtils.dateMath("year", -1);
		}
		if (endTime == null || "".equals(endTime)) {
			endTime = DateFormatUtils.Date2StrFinalNow(new Date());
		}
		JSONObject res = new JSONObject();
		JSONObject data = new JSONObject();
		String companyId = UserContext.get().getCompanyId();
		List<BtPlanEntry> planEntrys = service.getPlanEntrysBySankey(companyId, startTime, endTime);
		if (planEntrys == null) {
			res.put("state", false);
			res.put("msg", "系统错误，获取计划货物地点数据失败！");
			return res;
		} else if (planEntrys.size() == 0) {
			res.put("state", false);
			res.put("msg", "计划货物地点无数据返回！");
			return res;
		} else {
			Map<String, EChartsVo> nodes = new HashMap<String, EChartsVo>();
			Map<String, EChartsVo> links = new HashMap<String, EChartsVo>();
			Map<String, List<BtPlanEntry>> groupMap = planEntrys.stream()
					.collect(Collectors.groupingBy(BtPlanEntry::getPlanId));
			for (Map.Entry<String, List<BtPlanEntry>> entry : groupMap.entrySet()) {
				List<BtPlanEntry> itValue = entry.getValue();
				List<BtPlanEntry> planEntrySorted = itValue.stream().sorted(Comparator.comparing(BtPlanEntry::getSign))
						.collect(Collectors.toList());
				if (planEntrySorted.size() > 2) {
					for (int i = 0; i < planEntrySorted.size(); i++) {
						if (i == planEntrySorted.size() - 1) {
							break;
						} else {
							EChartsVo nodesValue1 = new EChartsVo();
							nodesValue1.setId(planEntrySorted.get(i).getAddressId());
							nodesValue1.setName(planEntrySorted.get(i).getAddressName());
							nodes.put(planEntrySorted.get(i).getAddressId(), nodesValue1);
							EChartsVo nodesValue2 = new EChartsVo();
							nodesValue2.setId(planEntrySorted.get(i + 1).getAddressId());
							nodesValue2.setName(planEntrySorted.get(i + 1).getAddressName());
							nodes.put(planEntrySorted.get(i + 1).getAddressId(), nodesValue2);
							EChartsVo linksValue = new EChartsVo();
							String id = planEntrySorted.get(i).getAddressId() + "-"
									+ planEntrySorted.get(i + 1).getAddressId();
							String name = planEntrySorted.get(i).getAddressName() + "-"
									+ planEntrySorted.get(i + 1).getAddressName();
							linksValue.setId(id);
							linksValue.setName(name);
							linksValue.setNumber(planEntrySorted.get(i + 1).getDays() == 0 ? 1
									: planEntrySorted.get(i + 1).getDays());
							linksValue.setSource(planEntrySorted.get(i).getAddressId() + "-"
									+ planEntrySorted.get(i).getAddressName());
							linksValue.setTarget(planEntrySorted.get(i + 1).getAddressId() + "-"
									+ planEntrySorted.get(i + 1).getAddressName());
							links.put(id, linksValue);
						}
					}
				} else {
					EChartsVo eChartsVo1 = new EChartsVo();
					eChartsVo1.setId(planEntrySorted.get(0).getAddressId());
					eChartsVo1.setName(planEntrySorted.get(0).getAddressName());
					nodes.put(planEntrySorted.get(0).getAddressId(), eChartsVo1);

					EChartsVo eChartsVo2 = new EChartsVo();
					eChartsVo2.setId(planEntrySorted.get(1).getAddressId());
					eChartsVo2.setName(planEntrySorted.get(1).getAddressName());
					nodes.put(planEntrySorted.get(1).getAddressId(), eChartsVo2);

					EChartsVo eChartsVo3 = new EChartsVo();
					String id = planEntrySorted.get(0).getAddressId() + "-" + planEntrySorted.get(1).getAddressId();
					String name = planEntrySorted.get(0).getAddressName() + "-"
							+ planEntrySorted.get(1).getAddressName();
					eChartsVo3.setId(id);
					eChartsVo3.setName(name);
					eChartsVo3.setNumber(planEntrySorted.get(1).getDays() == 0 ? 1 : planEntrySorted.get(1).getDays());
					eChartsVo3.setSource(
							planEntrySorted.get(0).getAddressId() + "-" + planEntrySorted.get(0).getAddressName());
					eChartsVo3.setTarget(
							planEntrySorted.get(1).getAddressId() + "-" + planEntrySorted.get(1).getAddressName());
					links.put(id, eChartsVo3);
				}
			}
			data.put("nodes", new ArrayList<EChartsVo>(nodes.values()));
			data.put("links", new ArrayList<EChartsVo>(links.values()));
		}
		res.put("state", true);
		res.put("data", data);
		return res;
	}

	/**
	 * 获取bar数据
	 * 
	 * @return JSON
	 */
	@RequestMapping("/getBar")
	@ResponseBody
	public JSONObject getBar(@RequestParam(value = "startTime", required = true, defaultValue = "") String startTime,
			@RequestParam(value = "endTime", required = true, defaultValue = "") String endTime,
			@RequestParam(value = "project", required = true, defaultValue = "all") String project) {
		log.info("获取bar数据");
		if (startTime == null || "".equals(startTime)) {
			startTime = DateFormatUtils.dateMath("year", -1);
		}
		if (endTime == null || "".equals(endTime)) {
			endTime = DateFormatUtils.Date2StrFinalNow(new Date());
		}
		JSONObject res = new JSONObject();
		JSONObject data = new JSONObject();
		String companyId = UserContext.get().getCompanyId();
		List<BtPlanEntry> planEntrys = service.getPlanEntrysByBar(companyId, startTime, endTime);
		if (planEntrys == null) {
			res.put("state", false);
			res.put("msg", "系统错误，获取计划异常分析数据失败！");
			return res;
		} else if (planEntrys.size() == 0) {
			res.put("state", false);
			res.put("msg", "计划异常分析无数据返回！");
			return res;
		} else {
			Map<String, List<BtPlanEntry>> groupMap = planEntrys.stream()
					.collect(Collectors.groupingBy(BtPlanEntry::getPlanId));
			List<EChartsVo> eChartsVo = new ArrayList<EChartsVo>();
			// 判断时间有几个月
//			int dateMathNumber = DateFormatUtils.dateMathNumber(DateFormatUtils.Str2Date(startTime),
//					DateFormatUtils.Str2Date(endTime), "year");
			for (int j = 1; j < 13 + 1; j++) {
				EChartsVo e = new EChartsVo();
				e.setType(j);
				e.setNumber(0);
				eChartsVo.add(e);
			}
			Map<Integer, Integer> monthMap = eChartsVo.stream()
					.collect(Collectors.toMap(EChartsVo::getType, EChartsVo::getNumber));
			Map<Integer, Integer> exceptionMap = eChartsVo.stream()
					.collect(Collectors.toMap(EChartsVo::getType, EChartsVo::getNumber));
			Map<Integer, Integer> noExceptionMap = eChartsVo.stream()
					.collect(Collectors.toMap(EChartsVo::getType, EChartsVo::getNumber));
			for (Map.Entry<String, List<BtPlanEntry>> entry : groupMap.entrySet()) {
				String planId = entry.getKey();
				List<BtPlanEntry> itValue = entry.getValue();
				List<EChartsVo> month = service.getBarNumber(startTime, endTime, planId);
				Map<Integer, Integer> monthMapByPlanId = month.stream()
						.collect(Collectors.toMap(EChartsVo::getType, EChartsVo::getNumber));
				for (Map.Entry<Integer, Integer> map : monthMapByPlanId.entrySet()) {
					int sum = map.getValue().intValue() + monthMap.get(map.getKey()).intValue();
					boolean isException = itValue.stream().anyMatch(i -> i.getStates() == 1);
					// 总量
					monthMap.put(map.getKey(), sum);
					if (isException) {
						// 有异常
						exceptionMap.put(map.getKey(), sum);
					} else {
						// 无异常
						noExceptionMap.put(map.getKey(), sum);
					}
				}
			}
			// map转list
			List<Integer> sumList = monthMap.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey()))
					.map(e -> e.getValue()).collect(Collectors.toList());
			List<Integer> normalList = noExceptionMap.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey()))
					.map(e -> e.getValue()).collect(Collectors.toList());
			List<Integer> exceptionList = exceptionMap.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey()))
					.map(e -> e.getValue()).collect(Collectors.toList());
			data.put("sum", sumList);
			data.put("normal", normalList);
			data.put("exception", exceptionList);
		}
		res.put("data", data);
		res.put("state", true);
		return res;
	}

	/**
	 * 获取pie数据
	 * 
	 * @return JSON
	 */
	@RequestMapping("/getPie")
	@ResponseBody
	public JSONObject getPie(@RequestParam(value = "startTime", required = true, defaultValue = "") String startTime,
			@RequestParam(value = "endTime", required = true, defaultValue = "") String endTime,
			@RequestParam(value = "project", required = true, defaultValue = "all") String project) {
		log.info("获取pie数据");
		if (startTime == null || "".equals(startTime)) {
			startTime = DateFormatUtils.dateMath("year", -1);
		}
		if (endTime == null || "".equals(endTime)) {
			endTime = DateFormatUtils.Date2StrFinalNow(new Date());
		}
		String companyId = UserContext.get().getCompanyId();
		JSONObject res = new JSONObject();
		JSONObject data = new JSONObject();
		List<EChartsVo> innerData = service.getPie("inner", companyId, startTime, endTime);
		List<EChartsVo> outerData = service.getPie("outer", companyId, startTime, endTime);
		if (innerData == null || outerData == null) {
			res.put("state", false);
			res.put("msg", "系统错误，获取容器使用比例数据失败！");
			return res;
		} else if (innerData.size() == 0 || outerData.size() == 0) {
			res.put("state", false);
			res.put("msg", "容器使用比例无数据返回！");
			return res;
		} else {
			List<EChartsVo> sortedList = outerData.stream()
					.sorted(Comparator.comparing(EChartsVo::getNumber).reversed()).collect(Collectors.toList());
			if (outerData.size() > 8) {
				// JDK8 流操作无默认获取索引实现
				for (int i = 0; i < sortedList.size(); i++) {
					if (i > 7) {
						sortedList.get(i).setSelected(false);
					} else {
						sortedList.get(i).setSelected(true);
					}
				}
			} else {
				sortedList.stream().forEach(item -> item.setSelected(true));
			}
			data.put("innerData", innerData);
			data.put("outerData", sortedList);
		}
		res.put("data", data);
		res.put("state", true);
		return res;
	}

}
